package gazzera.commandline;

import gazzera.gui.*;
import gazzera.gui.messages.*;
import gazzera.utils.*;

import java.io.*;
import java.text.*;
import java.util.*;

import org.naturalcli.*;
import org.naturalcli.commands.*;

public class Headless implements GuiInterface
{
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");

	@Override
	public synchronized void pass(GuiMessage cmd)
	{
		System.out.println(sdf.format(new Date(System.currentTimeMillis()))+" "+cmd);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception
	{
		String keystore = "headless.keystore";
		if(args.length>0) keystore = args[0];
		Headless h = new Headless();
		
		final GuiInterface gui = CoreFactory.createCore(new File(keystore), h);
		
		addShutdownHook(gui);
		gui.pass(new Status());

		Set<Command> cs = buildCommands(gui);

		NaturalCLI cli = new NaturalCLI(cs);
		  BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
		  String s;
		  System.out.println("==============");
		  System.out.println("Type help for help");
		  System.out.print(">");
		  while ((s=r.readLine())!=null)
		  {
			  //String[] x = s.split(" ");
			  try
			{
				  if(s.equals("quit"))
				  {
				      gui.pass(new Quit());
					  break;
				  }
				cli.execute(s);
			}
			catch (Exception e)
			{
				System.out.println(e.getMessage());
			}
			  System.out.print(">");
		  }
	}

	private static Set<Command> buildCommands(final GuiInterface gui) throws InvalidSyntaxException
	{
		Set<Command> cs = new HashSet<Command>();
		cs.add( new Command("connect <host:string> <port:integer>", "Connect to a location", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new ConnectUrl((String)pr.getParameterValue(0), ((Integer)pr.getParameterValue(1)).intValue()));
			}
		}));
		
		cs.add( new Command("connect <hash:string>", "Connect to a node", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new ConnectNode((String)pr.getParameterValue(0)));
			}
		}));
		
		cs.add( new Command("chat <hash:string> <text:string>", "Send a chat message", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new ChatMessage((String)pr.getParameterValue(0), (String)pr.getParameterValue(1)));
			}
		}));
		
		cs.add( new Command("trust <hash:string>", "Toggle trust to a node", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new ToggleTrust((String)pr.getParameterValue(0)));
			}
		}));
		cs.add( new Command("editshare <id:integer> <folder:string> [<groups:string>]", "Edit a shared folder. ID=-1 means new one. Groups: comma separated, no space.", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
			    int id = (Integer)pr.getParameterValue(0);
			    String folder = (String)pr.getParameterValue(1);
			    List<String> g;
			    if(pr.getParameterCount()==2)
			    {
				g = new ArrayList<String>();
			    }
			    else
			    {
				String groups = (String)pr.getParameterValue(2);
				g = Arrays.asList(groups.split(","));
			    }
			    gui.pass(new EditShare(id, folder, g));
			}
		}));
		
		cs.add( new Command("groups <hash:string> [<groups:string>]", "Change the groups of a friend. Groups: comma separated, no space.", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
			    String hash = (String)pr.getParameterValue(0);
			    List<String> g;
			    if(pr.getParameterCount()==1)
			    {
				g = new ArrayList<String>();
			    }
			    else
			    {
				String groups = (String)pr.getParameterValue(1);
				g = Arrays.asList(groups.split(","));
			    }
			    gui.pass(new ChangeNodeGroups(hash, g));
			}
		}));
		
		cs.add( new Command("add friend <gid:string>", "Add a friend", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new AddFriend((String)pr.getParameterValue(0)));
			}
		}));
		
		cs.add( new Command("browse <gid:string> <parent:string>", "Browse file of a friend", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new GuiStartBrowseSearch((String)pr.getParameterValue(0), (String)pr.getParameterValue(1)));
			}
		}));
		
		cs.add( new Command("refresh shares", "Refresh shared folders", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new RefreshShares());
			}
		}));
		
		cs.add( new Command("download <hash:string> <name:string> <size:long>", "Start a download", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new NewDownload( new Hash((String)pr.getParameterValue(0)), (String)pr.getParameterValue(1), (Long)pr.getParameterValue(2), "", ""   ));
			}
		}));
		cs.add( new Command("cancel <id:integer>", "Cancel a download", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new CancelDownload((Integer)pr.getParameterValue(0)));
			}
		}));
		
		cs.add( new Command("remove friend <gid:string>", "Remove a friend or person", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new RemoveFriend((String)pr.getParameterValue(0)));
			}
		}));
		
		cs.add( new Command("quit", "Quit the core", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new Quit());
			}
		}));
		
		cs.add( new Command("status", "Receive complete status", new ICommandExecutor()
		{
			@Override
			public void execute(ParseResult pr) throws ExecutionException
			{
				gui.pass(new Status());
			}
		}));
		
		cs.add(new HelpCommand(cs));
		return cs;
	}

	private static void addShutdownHook(final GuiInterface gui)
	{
		Runnable r = new Runnable()
		{
			@Override
			public void run()
			{

				try
				{
				    gui.pass(new Quit());
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}

			}
		};
		Runtime.getRuntime().addShutdownHook(new Thread(r));
	}
	
	
}
